package com.izhengyin.miaosha.service.impl;
import com.izhengyin.miaosha.service.TokenService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.ReactiveStringRedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.util.DigestUtils;
import reactor.core.publisher.Mono;
import java.time.Duration;
import java.time.Instant;

@Service
@Slf4j
public class RedisTokenService implements TokenService {
    private final String TOKEN_PREFIX = "TOKEN_";
    private final String TOKEN_SEPARATOR = "@";
    @Value("${spring.application.tokenSurvivalSecond}")
    private int tokenSurvivalSecond;
    private final ReactiveStringRedisTemplate reactiveStringRedisTemplate;
    @Value("${spring.application.signature}")
    private String signature;
    public RedisTokenService(ReactiveStringRedisTemplate reactiveStringRedisTemplate) {
        this.reactiveStringRedisTemplate = reactiveStringRedisTemplate;
    }

    @Override
    public Mono<String> get(String queueNumber) {
        return this.reactiveStringRedisTemplate
                .opsForValue()
                .get(getRedisKey(queueNumber));
    }

    @Override
    public Mono<String> generate(String queueNumber) {
        long expireAt = Instant.now().getEpochSecond() + tokenSurvivalSecond;
        String token = createCiphertext(queueNumber,expireAt)+TOKEN_SEPARATOR+expireAt;
        return this.reactiveStringRedisTemplate
                .opsForValue()
                .set(getRedisKey(queueNumber),token, Duration.ofSeconds(tokenSurvivalSecond))
                .filter(Boolean::booleanValue)
                .map(bool -> token);
    }

    @Override
    public Boolean verify(String queueNumber , String token) {
        if (!token.contains(TOKEN_SEPARATOR)){
            return false;
        }
        String[] arr = token.split(TOKEN_SEPARATOR);
        String ciphertext = arr[0];
        long expireAt = Long.parseLong(arr[1]);
        //检查token是否过期
        if (expireAt < Instant.now().getEpochSecond()){
            if(log.isDebugEnabled()){
                log.info("token {} 已经过期",token);
            }
            return false;
        }
        if(!createCiphertext(queueNumber,expireAt).equals(ciphertext)){
            if(log.isDebugEnabled()){
                log.info("token {} 密文验证失败",token);
            }
            return false;
        }
        return true;
    }

    /**
     * 获取Redis存储的Key
     * @param queueNumber
     * @return
     */
    private String getRedisKey(String queueNumber){
        return TOKEN_PREFIX+queueNumber;
    }
    /**
     * 生成密文
     * @param queueNumber
     * @param expireAt
     * @return
     */
    private String createCiphertext(String queueNumber , long expireAt){
        StringBuilder builder = new StringBuilder();
        String hexStr = builder.append(queueNumber)
                .append(expireAt)
                .append(signature)
                .toString();
        return DigestUtils.md5DigestAsHex(hexStr.getBytes());
    }


}

